/*
   This module will create debugfs example module,
   the directory tree will be created,like:
   /sys/kernel/debug      (The debugfs mount node)
   |_slam_debug    
       |
       |_slam
       |   |_array
       |_array
       |_u8
*/
#include <linux/module.h>
#include <linux/debugfs.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

#define MAX_SLAM_SIZE 32

static struct dentry * slam_debug_dir, * slam_dir;
static u8 u8_var;
static char array[32] = "Hello xinu!\n";
static struct debugfs_blob_wrapper bw;

static int slam_open(struct inode *inode, struct file *filp)
{
	filp->private_data = inode->i_private;
	return 0;
}

static ssize_t slam_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
	if(*ppos >= MAX_SLAM_SIZE)
	      return 0;
	
	if(*ppos + count > MAX_SLAM_SIZE)
	      count = MAX_SLAM_SIZE - *ppos;

	if(copy_to_user(buf, array + *ppos, count))
	      return -EFAULT;

	*ppos += count;

	return count;
}

static ssize_t slam_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
        if(*ppos >= MAX_SLAM_SIZE)
                return 0;

	if(*ppos + count > MAX_SLAM_SIZE)
	        count = MAX_SLAM_SIZE - *ppos;

	if(copy_from_user(array + *ppos, buf, count))
	        return -EFAULT;

	*ppos += count;

	return count;
}

static struct file_operations slam_array_fops = 
{
	.owner = THIS_MODULE,
	.open  = slam_open,
	.read  = slam_read,
	.write = slam_write,
};

static int __init debugfs_example_init(void)
{
	slam_debug_dir = debugfs_create_dir("slam_debug", NULL);

	bw.data = (void *)array;
	bw.size = strlen(array) + 1;
	debugfs_create_blob("array", 0644, slam_debug_dir, &bw);

	slam_dir = debugfs_create_dir("slam", slam_debug_dir);
	debugfs_create_u8("u8", 0644, slam_debug_dir, &u8_var);
	debugfs_create_file("array", 0644, slam_dir, NULL, &slam_array_fops);

	return 0;
}

static void __exit debugfs_example_exit(void)
{
	debugfs_remove_recursive(slam_debug_dir);
}

module_init(debugfs_example_init);
module_exit(debugfs_example_exit);
